import configs from '@/utils/configs';

export const localtoken = {
  get() {
    return window.localStorage.getItem('token');
  },
  set(token: string) {
    window.localStorage.setItem('token', token);
  },
  del() {
    window.localStorage.removeItem('token');
  }
};

/*
 * 增强方法，获取年月日时分秒，多种格式
 * example: formatDate('yy-mm-dd hh:ii:ss', 1486623999);
 *          formatDate('yy年mm月dd日 hh时ii分ss秒', 1486623999);
 *          formatDate('yy年mm月dd日', 1486623999);
 *          formatDate(1486623999);
 *          formatDate();
 *          or more use method...
 * */
export const formatDate: (...payload: any[]) => string = (
  ...payload: any[]
): string => {
  let dateType: string = 'yy-mm-dd hh:ii:ss';
  let dateTime: Date;
  let timestamp: number;

  let reg_xx: RegExp,
    reg_x: RegExp,
    xx: any = null,
    x: any = null;

  // 验证纯数字
  const reg_num: RegExp = /^\d{1,}$/;

  // 判断有无参数
  if (payload.length) {
    // 验证类型
    if (reg_num.test(payload[0])) {
      // 判断时间戳长度
      if (String(payload[0]).length <= 10) {
        timestamp = payload[0] * 1000;
      } else {
        timestamp = +payload[0];
      }
    } else {
      dateType = payload[0];
      timestamp = payload[1] || Date.now();
    }
    dateTime = new Date(timestamp);
  } else {
    // 没传参数
    dateTime = new Date();
    timestamp = Date.now();
  }

  /*format: yyyy*/
  reg_xx = /yy{1}/gi;
  reg_x = /y{1}/gi;
  if (reg_xx.test(dateType)) {
    xx = dateTime.getFullYear();
    dateType = dateType.replace(reg_xx, xx);
  } else if (reg_x.test(dateType)) {
    x = dateTime.getFullYear();
    dateType = dateType.replace(reg_x, x);
  }

  /*format: mm|m*/
  reg_xx = /mm{1}/gi;
  reg_x = /m{1}/gi;
  if (reg_xx.test(dateType)) {
    xx =
      dateTime.getMonth() + 1 > 9
        ? dateTime.getMonth() + 1
        : '0' + (dateTime.getMonth() + 1);
    dateType = dateType.replace(reg_xx, xx);
  } else if (reg_x.test(dateType)) {
    x = dateTime.getMonth() + 1;
    dateType = dateType.replace(reg_x, x);
  }

  /*format: dd|d*/
  reg_xx = /dd{1}/gi;
  reg_x = /d{1}/gi;
  if (reg_xx.test(dateType)) {
    xx = dateTime.getDate() > 9 ? dateTime.getDate() : '0' + dateTime.getDate();
    dateType = dateType.replace(reg_xx, xx);
  } else if (reg_x.test(dateType)) {
    x = dateTime.getDate();
    dateType = dateType.replace(reg_x, x);
  }

  /*format: hh|h*/
  reg_xx = /hh{1}/gi;
  reg_x = /h{1}/gi;
  if (reg_xx.test(dateType)) {
    xx =
      dateTime.getHours() > 9 ? dateTime.getHours() : '0' + dateTime.getHours();
    dateType = dateType.replace(reg_xx, xx);
  } else if (reg_x.test(dateType)) {
    x = dateTime.getHours();
    dateType = dateType.replace(reg_x, x);
  }

  /*format: ii|i*/
  reg_xx = /ii{1}/gi;
  reg_x = /i{1}/gi;
  if (reg_xx.test(dateType)) {
    xx =
      dateTime.getMinutes() > 9
        ? dateTime.getMinutes()
        : '0' + dateTime.getMinutes();
    dateType = dateType.replace(reg_xx, xx);
  } else if (reg_x.test(dateType)) {
    x = dateTime.getMinutes();
    dateType = dateType.replace(reg_x, x);
  }

  /*format: ss|s*/
  reg_xx = /ss{1}/gi;
  reg_x = /s{1}/gi;
  if (reg_xx.test(dateType)) {
    xx =
      dateTime.getSeconds() > 9
        ? dateTime.getSeconds()
        : '0' + dateTime.getSeconds();
    dateType = dateType.replace(reg_xx, xx);
  } else if (reg_x.test(dateType)) {
    x = dateTime.getSeconds();
    dateType = dateType.replace(reg_x, x);
  }

  return dateType;
};

/**
 * 循环给对象赋值
 *
 * @param target 当前对象
 * @param source 新对象
 */
export const loopPropAssignment = <T>(target: T, source: T) => {
  let key: keyof typeof target;
  for (key in target) {
    // if (typeof source[key] === "undefined" || source[key] === null) continue;
    if (typeof source[key] === 'undefined') continue;
    target[key] = source[key];
  }
  return target;
};

/**
 * 格式化空字符串，返回横线
 *
 * @param str
 * @returns
 */
export const formatterEmptyString = (
  _row: any,
  _column: any,
  cellValue: string,
  _index: number
) => (typeof cellValue === 'string' && cellValue.length ? cellValue : '--');

/**
 * 通过url截取文件名称
 *
 * @param str
 * @returns
 */
export const getFilenameByUrl = (str: string) =>
  str.substring(str.lastIndexOf('/') + 1);

/**
 * 格式化ID，填充零
 * @param id
 * @returns
 */
export const formatterFillId = (id: number) => {
  // 大于等于6位数则不填充
  const fillStr = '000000';
  const leng = String(id).length;
  return fillStr.substring(leng) + String(id);
};

/**
 * 判断url是否需要拼接origin
 * @param origin
 * @param url
 */
export const formatWebUrl = (url: string, origin?: string) => {
  const res = /^(http|https|\/\/)/.test(url)
    ? url
    : (origin || configs.MEDIA_BASE_URL) + (/^\//.test(url) ? '' : '/') + url;
  return res;
};

/**
 * 创建小程序的任务状态
 * @param status
 */
export const formatMPTaskStatus = (status: number): string => {
  const opts: any = {
    0: '请使用微信扫描二维码',
    1: '生成任务',
    2: '任务超时',
    3: '任务已经被用户拒绝',
    4: '用户同意创建',
    5: '已经发起人脸流程',
    6: '人脸认证失败',
    7: '人脸认证ok',
    8: '人脸认证后，已经提交手机号码下发验证码',
    9: '手机验证失败',
    10: '手机号验证成功后，提交了创建',
    11: '创建失败',
    12: '创建成功',
    1001: '主体创建小程序数量达到上限',
    1002: '主体违规命中黑名单',
    1003: '管理员绑定账号数量达到上限',
    1004: '管理员违规命中黑名单',
    1005: '管理员手机绑定账号数量达到上限',
    1006: '管理员手机号违规命中黑名单',
    1007: '管理员身份证创建账号数量达到上限',
    1008: '管理员身份证违规命中黑名单'
  };
  return opts[status] || '请使用微信扫描二维码';
};

/**
 * 从字符串中，获取某个标签的某个属性的内容
 *
 * @param htmlStr html字符串
 * @param tagName 标签名
 * @param attrName 属性名
 *
 * @returns string 属性值
 */
export const getAttrValByHtml = (
  htmlStr: string,
  tagName: string,
  attrName: string
) => {
  const regStr = new RegExp(
    `<${tagName}(?:[^'">]*(?:"[^"]*"|'[^']*')(?<! ${attrName}=))*[^'">]* ${attrName}=(?:'([^']+)'|"([^"]+)"|([^'" <>]+)).*(?:>[^<>]*<\/${tagName}|\/)>`
  );
  return htmlStr.match(regStr)?.slice(1, 4).filter(Boolean)[0] ?? '';
};

/**
 * 生成随机字符串
 *
 * @param {number} len 长度，默认6位随机字符串
 * @returns
 */
export const createRandomStr = (
  len: number = 6,
  mode?: 'simple' | 'complex' | 'specific'
) => {
  // 默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1
  // const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';

  // 只要大写和数字
  let chars = '';

  switch (mode) {
    case 'simple':
      // 简单好记
      chars = 'ABCDEFGHJKMNPQRSTWXYZ2345678';
      break;
    case 'complex':
      // 复杂的
      chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
      break;
    case 'specific':
      // 含特殊符号
      chars =
        'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()+-={}[]';
      break;
    default:
      chars = 'ABCDEFGHJKMNPQRSTWXYZ2345678';
      break;
  }

  let str = '';

  for (let i = 0; i < len; i++) {
    str += chars.charAt(Math.floor(Math.random() * chars.length));
  }

  return str;
};

/**
 * 根据时间戳，获取当天开始时间戳和结束时间戳
 *
 * @param timestamp
 *
 * @returns 返回时间戳
 */
export const getRangeDateTimeByTime = (timestamp: string | number) => {
  // 小时区
  const tempHour = 8 * 60 * 60 * 1000;
  const daySecond = 86400 * 1000;

  // 根据时间戳，计算整点时间戳 (yyyy/MM/DD 00:00:00)
  let startTime = calcSubtract(timestamp, +timestamp % daySecond);
  startTime = calcSubtract(startTime, tempHour);

  // 根据时间戳，计算 (yyyy/MM/DD 23:59:59)
  const endTime = calcAdd(startTime, daySecond - 1000);

  return {
    startTime,
    endTime
  };
};

/**
 * 根据时间范围，生成每天的时间戳
 *
 * @param startTime
 * @param endTime
 *
 * @returns 返回每天的时间戳
 */
export const createDayTimeByRange = (
  startTime: string | number,
  endTime: string | number
): number[] => {
  // 生成时间列表
  const timestampList: number[] = [];
  const daySecond = 86400 * 1000;
  const dayLeng = (+endTime - +startTime) / daySecond;
  for (let i = 0; i <= dayLeng; i++) {
    timestampList.push(+startTime + daySecond * i);
  }
  return timestampList;
};

// 运算函数工具集
const calcOperateUtils = {
  /**
   * 根据倍数进行放大
   *
   * @param target 目标数据
   * @param pow 放大倍数（10的次方）
   */
  getZoomInResult: (target: string, pow = 4) => {
    if (!pow) return String(target);

    const numList = target.split('.');
    const preStr = numList[0];
    const lastStr = numList[1];

    // 若没有小数位
    if (!lastStr) {
      // 填充0
      const fillStr = Array(pow).fill('0').join('');
      return preStr + fillStr;
    }

    // 若小数位长度相等
    if (lastStr.length === pow) return numList.join('');

    // 填补剩余长度
    const fillStr = Array(pow - lastStr.length)
      .fill('0')
      .join('');
    return preStr + lastStr + fillStr;
  },

  /**
   * 根据倍数进行缩放
   *
   * @param target 目标数据
   * @param pow 放大倍数（10的次方）
   */
  getZoomOutResult: (target: number, pow = 4) => {
    if (!pow) return String(target);
    const level = String(target).length - pow;
    const preStr = String(target).substring(0, level) || 0;
    let lastStr = String(target).substring(level) || 0;
    // 删除多余的零（最少剩余1个）
    lastStr = String(lastStr).replace(/0+$/, '') || 0;
    if (level > 0) {
      const res = preStr + '.' + lastStr;
      // 去除多余零
      return `${+res}`;
    } else {
      // 根据次方数生成替补字符串
      const fillStr = Array(Math.abs(level)).fill('0').join('');
      return preStr + '.' + fillStr + lastStr;
    }
  },

  // 比较两个小数，得出最大倍数的次方
  getContrastPow: (baseNum: string, optionalNum: string = '') => {
    const baseIndex = baseNum.indexOf('.');
    const optionalIndex = optionalNum.indexOf('.');
    const baseLeng =
      baseIndex !== -1 ? baseNum.substring(baseIndex + 1).length : 0;
    const optionalLeng =
      optionalIndex !== -1
        ? optionalNum.substring(optionalIndex + 1).length
        : 0;
    return Math.max(baseLeng, optionalLeng);
  }
};

/**
 * 运算函数 - 加
 *
 * @param augend
 * @param addend
 * @returns
 */
export const calcAdd = (augend: number | string, addend: number | string) => {
  const pow = calcOperateUtils.getContrastPow(String(augend), String(addend));
  augend = +calcOperateUtils.getZoomInResult(String(augend), pow);
  addend = +calcOperateUtils.getZoomInResult(String(addend), pow);
  return calcOperateUtils.getZoomOutResult(augend + addend, pow);
};

/**
 * 运算函数 - 减
 *
 * @param minuend
 * @param subtrahend
 * @returns
 */
export const calcSubtract = (
  minuend: number | string,
  subtrahend: number | string
) => {
  const pow = calcOperateUtils.getContrastPow(
    String(minuend),
    String(subtrahend)
  );
  minuend = +calcOperateUtils.getZoomInResult(String(minuend), pow);
  subtrahend = +calcOperateUtils.getZoomInResult(String(subtrahend), pow);
  return calcOperateUtils.getZoomOutResult(minuend - subtrahend, pow);
};

/**
 * 运算函数 - 乘
 *
 * @param multiplier
 * @param multiplicand
 * @returns
 */
export const calcMultiply = (
  multiplier: number | string,
  multiplicand: number | string
) => {
  const pow = calcOperateUtils.getContrastPow(
    String(multiplier),
    String(multiplicand)
  );
  multiplier = +calcOperateUtils.getZoomInResult(String(multiplier), pow);
  multiplicand = +calcOperateUtils.getZoomInResult(String(multiplicand), pow);
  return calcOperateUtils.getZoomOutResult(multiplier * multiplicand, pow * 2);
};

/**
 * 运算函数 - 除
 *
 * @param dividend
 * @param divisor
 * @returns
 */
export const calcDivide = (
  dividend: number | string,
  divisor: number | string
) => {
  const pow = calcOperateUtils.getContrastPow(
    String(dividend),
    String(divisor)
  );
  dividend = +calcOperateUtils.getZoomInResult(String(dividend), pow);
  divisor = +calcOperateUtils.getZoomInResult(String(divisor), pow);
  return calcOperateUtils.getZoomOutResult(dividend / divisor, 0);
};
